from urllib.parse import urlencode

from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.http import HttpResponseForbidden, HttpResponseRedirect
from django.urls import reverse
from django.utils.deprecation import MiddlewareMixin

from django_sso.middleware.utils import get_auth_views
from django_sso.views import login as sso_login
from django_sso.views import logout as sso_logout


class CASMiddleware(MiddlewareMixin):
    """Middleware that allows CAS authentication on admin pages"""

    def process_request(self, request):
        """Checks that the authentication middleware is installed"""

        error = (
            "The Django CAS middleware requires authentication "
            "middleware to be installed. Edit your MIDDLEWARE_CLASSES "
            "setting to insert 'django.contrib.auth.middleware."
            "AuthenticationMiddleware'."
        )
        assert hasattr(request, "user"), error

    def process_view(self, request, view_func, view_args, view_kwargs):
        """Forwards unauthenticated requests to the admin page to the CAS
        login URL, as well as calls to django.contrib.auth.views.login and
        logout.
        """

        login, logout = get_auth_views()
        if view_func == login:
            return sso_login(request, settings, *view_args, **view_kwargs)
        elif view_func == logout:
            return sso_logout(request, settings, *view_args, **view_kwargs)

        if settings.CAS_ADMIN_PREFIX:
            if not request.path.startswith(settings.CAS_ADMIN_PREFIX):
                return None
        elif not view_func.__module__.startswith("django.contrib.admin."):
            return None

        if request.user.is_authenticated:
            if request.user.is_staff:
                return None
            else:
                error = "<h1>Forbidden</h1><p>You do not have staff privileges.</p>"
                return HttpResponseForbidden(error)

        params = urlencode({REDIRECT_FIELD_NAME: request.get_full_path()})
        return HttpResponseRedirect(reverse(sso_login) + "?" + params)
